﻿#include <libini/section.h>
#include <libini/string.h>


// constructor
Xanadu::ini::section::section() noexcept
{
	this->_memberComment.clear();
	this->_memberName = "";
	this->_memberItems.clear();
}

// constructor
Xanadu::ini::section::section(const std::string& _String) noexcept
{
	this->_memberComment.clear();
	this->_memberName = "";
	this->_memberItems.clear();
}

// constructor
Xanadu::ini::section::section(const Xanadu::ini::section& _Other) noexcept
{
	this->_memberComment = _Other._memberComment;
	this->_memberName = _Other._memberName;
	this->_memberItems = _Other._memberItems;
}

// destructor
Xanadu::ini::section::~section() noexcept
{
	this->_memberComment.clear();
	this->_memberItems.clear();
}



// operator overload =
Xanadu::ini::section& Xanadu::ini::section::operator = (const Xanadu::ini::section& _Other) noexcept
{
	this->_memberComment = _Other._memberComment;
	this->_memberName = _Other._memberName;
	this->_memberItems = _Other._memberItems;
	return *this;
}



// Set the data for the section
void Xanadu::ini::section::setData(const std::string& _String) noexcept
{
}

// Set the data for the section
void Xanadu::ini::section::setData(const char* _Bytes, std::size_t _Length) noexcept
{
	Xanadu::ini::section::setData(std::string(_Bytes, _Length));
}



// Get comment
std::string Xanadu::ini::section::comment() const noexcept
{
	return Xanadu::ini::explain::toString(this->_memberComment);
}

// Get section name
std::string Xanadu::ini::section::name() const noexcept
{
	return this->_memberName;
}



// Set comment
void Xanadu::ini::section::setComment(const std::string& _Comment) noexcept
{
	this->_memberComment = Xanadu::ini::explain::fromString(_Comment);
}

// Set section name
void Xanadu::ini::section::setName(const std::string& _Name) noexcept
{
	this->_memberName = _Name;
}



// Find key value
Xanadu::ini::item& Xanadu::ini::section::find(const std::string& _Key) noexcept
{
	static Xanadu::ini::item		_staticLineNull;
	auto 		vIterator = this->_memberItems.find(_Key);
	if(vIterator != this->_memberItems.end())
	{
		return vIterator->second;
	}
	return _staticLineNull;
}

// Find key value
const Xanadu::ini::item& Xanadu::ini::section::find(const std::string& _Key) const noexcept
{
	static Xanadu::ini::item		_staticLineNull;
	auto 		vIterator = this->_memberItems.find(_Key);
	if(vIterator != this->_memberItems.end())
	{
		return vIterator->second;
	}
	return _staticLineNull;
}

// Find key value
bool Xanadu::ini::section::find(const std::string& _Key, Xanadu::ini::item& _Item) const noexcept
{
	auto 		vIterator = this->_memberItems.find(_Key);
	if(vIterator != this->_memberItems.end())
	{
		_Item = vIterator->second;
		return true;
	}
	return false;
}

// Set key value
void Xanadu::ini::section::set(const std::string& _Key, const std::string& _Value) noexcept
{
	auto		vLine = this->find(_Key);
	if(vLine.empty())
	{
		auto 		vItem = Xanadu::ini::item();
		vItem.setKey(_Key);
		vItem.setValue(_Value);
		this->_memberItems.insert(std::map<std::string, Xanadu::ini::item>::value_type(_Key, vItem));
	}
	else
	{
		vLine.setValue(_Value);
	}
}

// Remove line
void Xanadu::ini::section::remove(const std::string& _Key) noexcept
{
	// Find current key
	auto 		vIterator = this->_memberItems.find(_Key);
	if(vIterator != this->_memberItems.end())
	{
		this->_memberItems.erase(vIterator);
	}
}



// Convert to string
std::string Xanadu::ini::section::toString() const noexcept
{
	auto		vString = this->comment() +  "[" + this->name() + "]" + LIBINI_NEWLINE_STRING;
	for(const auto & vIterator : _memberItems)
	{
		vString += vIterator.second.toString() + LIBINI_NEWLINE_STRING;
	}
	return vString;
}

// Format from one or more lines of strings
Xanadu::ini::section Xanadu::ini::section::fromStrings(const std::list<std::string>& _Strings) noexcept
{
	auto 		vSection = Xanadu::ini::section();
	auto 		vIterator = _Strings.begin();

	// Get comment and section
	auto 		vCommentStrings = std::list<std::string>();
	for(; vIterator != _Strings.end(); ++vIterator)
	{
		if(Xanadu::ini::string::is_empty(*vIterator) || Xanadu::ini::string::is_explain(*vIterator))
		{
			vCommentStrings.push_back(*vIterator);
		}
		if(Xanadu::ini::string::is_section(*vIterator))
		{
			vSection._memberName = Xanadu::ini::string::extract_section(*vIterator);
			++vIterator;
			break;
		}
	}
	vSection._memberComment = Xanadu::ini::explain::fromString(vCommentStrings);

	// Find the tag for the section
	auto 		vItemStrings = std::list<std::string>();
	for(; vIterator != _Strings.end(); ++vIterator)
	{
		vItemStrings.push_back(*vIterator);
	}

	// Split all children
	auto 		vItemArray = Xanadu::ini::section::split_item(vItemStrings);
	for(const auto & vItemData : vItemArray)
	{
		auto 		vItemObject = Xanadu::ini::item::fromStrings(vItemData);
		if(vItemObject.exist())
		{
			vSection._memberItems.insert(std::map<std::string, Xanadu::ini::item>::value_type(vItemObject.key(), vItemObject));
		}
	}

	return vSection;
}



// Analysis section, returns all key value
std::list<std::list<std::string>> Xanadu::ini::section::split_item(const std::list<std::string>& _Strings) noexcept
{
	auto 		vItemArray = std::list<std::list<std::string>>();

	// Reverse lookup section
	auto 		vFindEnd = _Strings.rbegin();
	for(auto vIterator = _Strings.rbegin(); vIterator != _Strings.rend();)
	{
		if(Xanadu::ini::string::is_key(*vIterator))
		{
			auto 		vItemData = std::list<std::string>(vIterator.base(), vFindEnd.base());
			vItemData.insert(vItemData.begin(), *vIterator);
			++vIterator;
			// Find all comments up
			while(vIterator != _Strings.rend() && (Xanadu::ini::string::is_empty(*vIterator) || Xanadu::ini::string::is_explain(*vIterator)))
			{
				vItemData.insert(vItemData.begin(), *vIterator);
				++vIterator;
			}
			vItemArray.insert(vItemArray.begin(), vItemData);
			vFindEnd = vIterator;
			if(vIterator == _Strings.rend())
			{
				break;
			}
		}
	}
	return vItemArray;
}
